#! /usr/bin/env python

'''Unit tests of the database_access module.

Mike Dorey  2011-04-04
'''


import database_access
import unittest
import MySQLdb
import MySQLdb.cursors


class DatabaseAccessTester(unittest.TestCase):
    '''Tests of the database_access module.'''


    def setUp(self):
        '''Connects to the database.'''
        self.connection, self.cursor = database_access.get_connection_and_cursor('localhost', 
                             'ccldas', '/home/dorey/.my.cnf')
        self.test_user_name = 'CCLDAS TESTING'
        self.test_experiment_name = 'Software test 1'
        self.chemical_comp = 'NICKEL'
        self.batch = '64'
        self.dust_type = database_access.DustType('NICKEL', '64')


    def tearDown(self):
        '''Disconnects from the database.'''
        self.connection.close()


    def test_fetch_all_user_names(self):
        '''Tests database_access.fetch_all_user_names.'''
        user_names = database_access.fetch_all_user_names(self.cursor)
        self.assertTrue(self.test_user_name in user_names)


    def test_fetch_user_experiment_names(self):
        '''Tests database_access.fetch_user_experiment_names.'''
        exp_names = database_access.fetch_user_experiment_names(self.cursor, self.test_user_name)
        self.assertTrue(len(exp_names) > 0)
        self.assertTrue(self.test_experiment_name in exp_names)


    def test_fetch_dust_experiment(self):
        '''Tests database_access.fetch_dust_experiment.'''
        experiment = database_access.fetch_dust_experiment(self.cursor, self.test_user_name, 
                          self.test_experiment_name)
        self.assertTrue(experiment.user_name == self.test_user_name)
        self.assertTrue(experiment.experiment_name == self.test_experiment_name)
        self.assertTrue(len(experiment.remarks) > 0)
        self.assertTrue(experiment.dust_type is not None)
        self.assertTrue(len(experiment.dust_events) > 0)
        event = experiment.dust_events[0]
        self.cursor.execute('''select * from dustevents where timestamp = %s''', 
                        (event.timestamp,))
        c = self.cursor.fetchone()
        self.assertEqual(c['timestamp'], event.timestamp)
        self.assertAlmostEqual(c['charge'], event.charge)
        self.assertAlmostEqual(c['lenspotential'], event.lenspotential)
        self.assertAlmostEqual(c['mass'], event.mass)
        self.assertAlmostEqual(c['needlepotential'], event.needlepotential)
        self.assertAlmostEqual(c['pulsefreq'], event.pulsefreq)
        self.assertAlmostEqual(c['pulseheight'], event.pulseheight)
        self.assertAlmostEqual(c['pulsewidth'], event.pulsewidth)
        self.assertEqual(c['selection'], event.selection)
        self.assertAlmostEqual(c['terminalpotential'], event.terminalpotential)
        self.assertAlmostEqual(c['velocity'], event.velocity)
        self.assertEqual(c['waveforms'], event.waveforms)
        # some prints just to exercise the __str__ methods
        print experiment
        print experiment.dust_type
        print event


    def test_get_remarks(self):
        '''Tests database_access.get_remarks.'''
        remarks = database_access.get_remarks(self.cursor, self.test_user_name, 
                      self.test_experiment_name)
        self.assertEqual(remarks, 'First test of the database link')


    def test_get_dust_type(self):
        '''Tests database_access.get_dust_types.'''
        dust_type = database_access.get_dust_type(self.cursor,
                 self.test_experiment_name)
        self.assertTrue(dust_type is not None)
        self.assertTrue(dust_type.chemical_comp == 'IRON')
        self.assertTrue(dust_type.batch == '112')


    def test_get_dust_type_ids(self):
        '''Tests database_access.get_dust_type_ids.'''
        dust_type_ids = database_access.get_dust_type_ids(self.cursor,
                        self.test_experiment_name)
        self.assertTrue(len(dust_type_ids) > 0)
        self.assertTrue(1 in dust_type_ids)


    #def test_fetch_dust_events(self):
    #    '''Tests database_access.fetch_dust_events.'''
    #    events = database_access.fetch_dust_events(self.cursor,
    #              self.test_user_name, self.test_experiment_name,
    #              3384479168509L, 3384479178509L)
    #    self.assertTrue(len(events) > 0)
    #    timestamps = [e.timestamp for e in events]
    #    self.assertTrue(min(timestamps) >= 3384479168509L)
    #    self.assertTrue(max(timestamps) <= 3384479178509L)


    def test_get_dust_type_time_periods(self):
        '''Tests database_access.get_dust_type_time_periods.'''
        time_periods = database_access.get_dust_type_time_periods(
                           self.cursor)
        self.assertTrue(len(time_periods) > 0)
        for tp in time_periods:
            self.assertTrue(len(tp) == 3)
            # test that the first thing in the tuples is not a timestamp
            self.assertTrue(tp[0] < 100000) 

    def test_times_overlap(self):
        '''Tests database_access.times_overlap.'''
        (a,b) = (1,2)
        (c,d) = (3,4)
        self.assertFalse(database_access.times_overlap((a,b), (c,d)))
        self.assertFalse(database_access.times_overlap((c,d), (a,b)))
        (a,b) = (1,2)
        (c,d) = (2,4)
        self.assertTrue(database_access.times_overlap((a,b), (c,d)))
        self.assertTrue(database_access.times_overlap((c,d), (a,b)))
        (a,b) = (1,5)
        (c,d) = (2,4)
        self.assertTrue(database_access.times_overlap((a,b), (c,d)))
        self.assertTrue(database_access.times_overlap((c,d), (a,b)))
        (a,b) = (2,5)
        (c,d) = (1,6)
        self.assertTrue(database_access.times_overlap((a,b), (c,d)))
        self.assertTrue(database_access.times_overlap((c,d), (a,b)))
        (a,b) = (1,3)
        (c,d) = (2,4)
        self.assertTrue(database_access.times_overlap((a,b), (c,d)))
        self.assertTrue(database_access.times_overlap((c,d), (a,b)))


    def test_current_labview_time(self):
        '''Tests database_access.current_labview_time.'''
        t = database_access.current_labview_time()
        self.assertTrue(t > 3385099731000L)


    def test_time_periods_from_change_times(self):
        '''Tests database_access.time_periods_from_change_times.'''
        change_times = [(1, 1), (2, 2), (3, 2), (4, 3)]
        time_periods = [p for p in 
               database_access.time_periods_from_change_times(change_times)]
        self.assertTrue(len(time_periods) == 3)
        self.assertTrue((1, 1, 2) == time_periods[0])
        self.assertTrue((2, 2, 4) == time_periods[1])
        self.assertTrue((3, 4) == time_periods[2][:2]) 
        self.assertTrue(time_periods[2][2] > 3385099731000L)


    def test_fetch_dust_events_that_meet_timetag_criteria(self):
        '''Tests database_access.fetch_dust_events_that_meet_criteria for timetags.'''
        criteria = {'timestamp_groups': 
                     [[(3384479158508L, 3384479258508L)],
                      [(3384479168508L, 3384495986278L),
                       (3384495986278L, 3385100394000L)]]}
        events = database_access.fetch_dust_events_that_meet_criteria(
                     self.cursor, criteria)
        self.assertTrue(max([e.timestamp for e in events]) <= 3384479258508L)


    def test_fetch_dust_events_that_meet_velocity_criteria(self):
        '''Tests database_access.fetch_dust_events_that_meet_criteria for velocities.'''
        criteria = {'lower_and_upper_velocities': [(4500, 4510)]}
        events = database_access.fetch_dust_events_that_meet_criteria(
                     self.cursor, criteria)
        self.assertTrue(min([e.velocity for e in events]) >= 4500)
        self.assertTrue(max([e.velocity for e in events]) <= 4510)


    def test_fetch_dust_events_that_meet_charge_criteria(self):
        '''Tests database_access.fetch_dust_events_that_meet_criteria for charges.'''
        criteria = {'lower_and_upper_charges': [(4.5, 4.52)]}
        events = database_access.fetch_dust_events_that_meet_criteria(
                     self.cursor, criteria)
        self.assertTrue(min([e.charge for e in events]) >= 4.5)
        self.assertTrue(max([e.charge for e in events]) <= 4.52)


    def test_fetch_dust_events_that_meet_mass_criteria(self):
        '''Tests database_access.fetch_dust_events_that_meet_criteria for mass.'''
        criteria = {'lower_and_upper_masses': [(9.5, 9.6)]}
        events = database_access.fetch_dust_events_that_meet_criteria(
                     self.cursor, criteria)
        self.assertTrue(min([e.mass for e in events]) >= 9.5)
        self.assertTrue(max([e.mass for e in events]) <= 9.6)


    def test_fetch_dust_events_that_meet_selection_criteria(self):
        '''Tests database_access.fetch_dust_events_that_meet_criteria for mass and selection.'''
        criteria = {'lower_and_upper_masses': [(9.5, 9.6)], 'selection': 0}
        events = database_access.fetch_dust_events_that_meet_criteria(
                     self.cursor, criteria)
        selection_set = set([e.selection for e in events])
        self.assertTrue(len(selection_set) == 1)
        self.assertTrue(max(selection_set) == 0)


    def test_timestamp_boundaries_for_user(self):
        '''Tests database_access.timestamp_boundaries_for_user.'''
        boundaries = database_access.timestamp_boundaries_for_user(self.cursor,
                          self.test_user_name)
        self.assertTrue(len(boundaries) > 0)


    def test_timestamp_boundaries_for_experiment(self):
        '''Tests database_access.timestamp_boundaries_for_experiment.'''
        boundaries = database_access.timestamp_boundaries_for_experiment(self.cursor,
                          self.test_experiment_name)
        self.assertTrue(len(boundaries) > 0)


    def test_timestamp_boundaries_from_config(self):
        '''Tests database_access.timestamp_boundaries_from_config.'''
        config = {'lower timestamp': 3384479158508L,
                  'upper timestamp': 3384495986278L}
        boundaries = database_access.timestamp_boundaries_from_config(
                          config)
        self.assertTrue(len(boundaries) > 0)
        config = {
                  'upper timestamp': 3384495986278L}
        boundaries = database_access.timestamp_boundaries_from_config(
                          config)
        self.assertTrue(len(boundaries) > 0)
        config = {'lower timestamp': 3384479158508L}
        boundaries = database_access.timestamp_boundaries_from_config(
                          config)
        self.assertTrue(len(boundaries) > 0)
        config = {}
        boundaries = database_access.timestamp_boundaries_from_config(
                          config)
        self.assertTrue(boundaries is None)


    def test_timestamp_boundaries_for_dust_type(self):
        '''Tests database_access.timestamp_boundaries_for_dust_type.'''
        boundaries = database_access.timestamp_boundaries_for_dust_type(self.cursor,
                          self.dust_type)
        self.assertTrue(len(boundaries) > 0)


if __name__ == "__main__":
    unittest.main()
